<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Equipment {
	public $atk, $matk, $def, $mdef;
	
	public function __construct($atk, $matk, $def, $mdef)
	{
		$this->atk = $atk;
		$this->matk = $matk;
		$this->def = $def;
		$this->mdef = $mdef;
	}
}

class Active_Skills {
	public $target, $caster;
	public $name, $description;
	var $hp_cost, $mp_cost, $ki_cost, $tc_multiplier, $no_of_hit;
	
	public function __construct($name, $description = "", $hp_cost = 0, $mp_cost = 0, $ki_cost = 0, $tc_multiplier = 1, $no_of_hit = 1)
	{
		$this->name = $name;
		$this->description = $description;
		$this->hp_cost = $hp_cost;
		$this->mp_cost = $mp_cost;
		$this->ki_cost = $ki_cost;
		$this->tc_multiplier = $tc_multiplier;
		$this->no_of_hit = $no_of_hit;
	}
	
	function isCastAble()
	{
		// TODO: If caster is not silenced
		if (($this->caster->hp - $this->hp_cost) > 0 && 
			($this->caster->mp - $this->mp_cost) >= 0 && 
			($this->caster->ki - $this->ki_cost) >= 0 )
		{
			return TRUE;
		}
	
		return FALSE;
	}
	
	function pay_cost()
	{
		if(isset($caster))
		{
			if($this->isCastAble())
			{
				$this->caster->hp -= $this->hp_cost;
				$this->caster->mp -= $this->mp_cost;
				$this->caster->ki -= $this->ki_cost;
				
				$this->caster->curr_tc += round($caster->b_tc * $this->tc_multiplier);
				
				return TRUE;
			}
		}
		
		return FALSE;
	}
}

// Single Target Skills
class ST_Skills extends Active_Skills {
	var $atk_multiplier, $matk_multiplier;
	
	public function __construct($name, $description = "", $hp_cost = 0, $mp_cost = 0, $ki_cost = 0, $tc_multiplier = 1, $no_of_hit = 1, $atk_multiplier, $matk_multiplier)
	{
		parent::__construct($name, $description, $hp_cost, $mp_cost, $ki_cost, $tc_multiplier, $no_of_hit);
		$this->atk_multiplier = $atk_multiplier;
		$this->matk_multiplier = $matk_multiplier;
	}
	
	public function execute()
	{
		$log = array();
		
		if($this->isCastAble())
		{
			$this->pay_cost();
			// ATK DAMAGE
			$p_dmg_reduction = (150 - $this->target->def) / 150;
			$p_damage = round(rand($this->caster->atk-2, $this->caster->atk+2) * $this->atk_multiplier * $p_dmg_reduction);
			
			// MATK DAMAGE
			$m_dmg_reduction = (150 - $this->target->mdef) / 150;
			$m_damage = round(rand($this->caster->matk-2, $this->caster->matk+2) * $this->matk_multiplier * $m_dmg_reduction);
			
			for($i=1; $i<$this->no_of_hit; $i++)
			{
				if ($p_damage > 0)
				{
					$this->target->hp -= $p_damage;
					array_push($log, array($this->name => array("from" => $this->caster->name, "to" => $this->target->name, "p_damage" => $p_damage)));
				}
				
				if ($m_damage > 0)
				{
					$this->target->hp -= $m_damage;
					array_push($log, array($this->name => array("from" => $this->caster->name, "to" => $this->target->name, "m_damage" => $m_damage)));
				}
			}
		}
		return $log;
	}
}

class Passive_Skills {
	public $caster;
}

class Battle_pos {
	public $x, $y;
	
	public function __construct($x = 0, $y = 0)
	{
		$this->x = $x;
		$this->y = $y;
	}
}

class Entity {
	public $name;
	public $max_hp, $max_mp, $max_ki;
	public $hp, $mp, $ki;
	public $b_atk, $b_matk, $b_def, $b_mdef, $b_tc;
	public $atk, $matk, $def, $mdef, $curr_tc;
	public $battle_pos;
	public $equipments;
	public $skills;
	
	public function __construct($name, $max_hp, $max_mp, $max_ki, $b_atk, $b_matk, $b_def, $b_mdef, $b_tc)
	{
		$this->name = $name;
		$this->max_hp = $max_hp;
		$this->max_mp = $max_mp;
		$this->max_ki = $max_ki;
		
		$this->hp = $max_hp;
		$this->mp = $max_mp;
		$this->ki = $max_ki;
		$this->curr_tc = $b_tc;
		
		$this->b_atk = $b_atk;
		$this->b_matk = $b_matk;
		$this->b_def = $b_def;
		$this->b_mdef = $b_mdef;
		$this->b_tc = $b_tc;
		
		$this->battle_pos = new Battle_pos(0, 0);
		$this->skills = array();
	}
	
	public function set_equipments($eq = array()) {
		if (sizeof($eq) > 0)
		{
			foreach($eq as $k => $v)
			{
				$this->equipments[$k] = $v;
			}
		}
	}
	
	
	public function set_position($x = 0, $y = 0) {
		$this->battle_pos->x = $x;
		$this->battle_pos->y = $y;
	}
	
	public function recalculate()
	{
		$this->atk = $this->get_total("atk");
		$this->matk = $this->get_total("matk");
		$this->def = $this->get_total("def");
		$this->mdef = $this->get_total("mdef");
	}
	
	public function addSkill($skill = NULL)
	{
		if($skill != NULL)
		{
			$skill->caster = $this;
			array_push($this->skills, $skill);
		}
	}
	
	public function addSkills($skills = array())
	{
		if(sizeof($skills) > 0)
		{
			foreach($skills as $skill)
			{
				$this->addSkill($skill);
			}
		}
	}
	
	function get_total($type)
	{
		switch(strtolower($type))
		{
			case "atk":
				$total = $this->b_atk;
				if(isset($this->equipments))
				{
					foreach($this->equipments as $equip)
					{
						$total += $equip->atk;
					}
				}
			break;
			
			case "matk":
				$total = $this->b_matk;
				if(isset($this->equipments))
				{
					foreach($this->equipments as $equip)
					{
						$total += $equip->matk;
					}
				}
			break;
			
			case "def":
				$total = $this->b_def;
				if(isset($this->equipments))
				{
					foreach($this->equipments as $equip)
					{
						$total += $equip->def;
					}
				}
			break;
			
			case "mdef":
				$total = $this->b_mdef;
				if(isset($this->equipments))
				{
					foreach($this->equipments as $equip)
					{
						$total += $equip->mdef;
					}
				}
			break;
			
			default:
				return NULL;
			break;
		}
		
		return $total;
	}
}

class Battle extends CI_Controller {
	public $player;
	public $monster;
	
	public $player_group;
	public $enemy_group;

	public function __construct()
	{
		parent::__construct();
		
		// Skill Configurations
		//($name, $description = "", $hp_cost = 0, $mp_cost = 0, $ki_cost = 0, $tc_multiplier, $atk_multiplier, $matk_multiplier)
		$fireball = new ST_Skills("Fireball", "A burning fire ball", 0, 24, 0, 1.34, 1, 0, 1.75);
		$frostbolt = new ST_Skills("Frost Bolt", "", 0, 60, 0, 2.15, 3, 0, 1.125);
		
		$bash = new ST_Skills("Bash", "A powerful impact", 0, 0, 12, 1.78, 1, 2.15, 0);
		$quadruple_blow = new ST_Skills("Quadruple Blow", "", 5, 0, 25, 2.49, 4, 1.085, 0);
		
		$double_combo = new ST_Skills("Double Combo", "Combination of Magic and Physical Attack", 15, 15, 15, 2.85, 2, 1.385, 1.385);
		
		// Player Group
		$this->player_group = array();
		$this->player_group[0] = new Entity("Reid Vanheath", 973, 203, 55, 62, 12, 28, 17, 472);
		$this->player_group[0]->set_position(1, 1);
		$this->player_group[0]->addSkill($bash);
		$this->player_group[0]->addSkill($quadruple_blow);
		$this->player_group[0]->addSkill($double_combo);
		
		//print_r($this->player_group[0]->skills);
		
		$this->player_group[1] = new Entity("Celia Gale", 741, 593, 0, 31, 99, 19, 39, 629);
		$this->player_group[1]->set_position(1, 2);
		$this->player_group[1]->addSkill($fireball);
		$this->player_group[1]->addSkill($frostbolt);
		$this->player_group[1]->addSkill($double_combo);
		
		// Enemey Group
		$this->enemy_group = array();
		$this->enemy_group[0] = new Entity("Volutto", 453, 620, 28, 29, 133, 11, 40, 617);
		$this->enemy_group[0]->set_position(1, 1);
		$this->enemy_group[0]->addSkill($fireball);
		$this->enemy_group[0]->addSkill($frostbolt);
		
		$this->enemy_group[1] = new Entity("Preggo", 781, 399, 28, 51, 53, 20, 20, 545);
		$this->enemy_group[1]->set_position(1, 2);
		$this->enemy_group[1]->addSkill($bash);
		$this->enemy_group[1]->addSkill($fireball);
		$this->enemy_group[1]->addSkill($double_combo);
		
		$this->enemy_group[2] = new Entity("Kirakas", 1490, 379, 70, 89, 49, 13, 9, 871);
		$this->enemy_group[2]->set_position(1, 3);
		$this->enemy_group[2]->addSkill($bash);
		$this->enemy_group[2]->addSkill($quadruple_blow);
		
		// Player's equipment
		$wand = new Equipment(10, 60, 0, 0);
		$dagger = new Equipment(29, 5, 0, 0);
		$sword = new Equipment(41, 0, 0, 0);
		
		$gale_coat = new Equipment(0, 0, 28, 20);
		$magic_robe = new Equipment(0, 0, 19, 35);
		
		$reid_equipments = array();
		$reid_equipments['weapon_r'] = $dagger;
		$reid_equipments['weapon_l'] = $sword;
		$reid_equipments['armor'] = $gale_coat;
		
		$celia_equipments = array();
		$celia_equipments['weapon_r'] = $wand;
		$celia_equipments['armor'] = $magic_robe;
		
		$this->player_group[0]->set_equipments($reid_equipments);
		$this->player_group[1]->set_equipments($celia_equipments);
	}
	
	public function index()
	{
		$this->load->view('welcome_message');
	}
	
	public function atk()
	{
		$this->calculate();
	}
	
	private function get_total($type, &$target)
	{
		switch(strtolower($type))
		{
			case "atk":
				$total = $target['b_atk'];
				if(isset($target['equipments']))
				{
					foreach($target['equipments'] as $equip)
					{
						$total += $equip->atk;
					}
				}
			break;
			
			case "matk":
				$total = $target['b_matk'];
				if(isset($target['equipments']))
				{
					foreach($target['equipments'] as $equip)
					{
						$total += $equip->matk;
					}
				}
			break;
			
			case "def":
				$total = $target['b_def'];
				if(isset($target['equipments']))
				{
					foreach($target['equipments'] as $equip)
					{
						$total += $equip->def;
					}
				}
			break;
			
			case "mdef":
				$total = $target['b_mdef'];
				if(isset($target['equipments']))
				{
					foreach($target['equipments'] as $equip)
					{
						$total += $equip->mdef;
					}
				}
			break;
			
			default:
				return NULL;
			break;
		}
		
		return $total;
	}
	
	private function calculate()
	{
		$log = array();
		$not_finished = false;
		while($not_finished != true)
		{
			$player_dead_count = 0;
			$enemy_dead_count = 0;
			
			foreach($this->player_group as $player)
			{
				if ($player->hp <= 0)
					$player_dead_count++;
				
				$player->recalculate();
			}
			
			if ($player_dead_count >= sizeof($this->player_group))
			{
				array_push($log, array("winner" => "Enemy Group"));
				$not_finished = true;
			}
		
			foreach($this->enemy_group as $enemy)
			{
				if ($enemy->hp <= 0)
					$enemy_dead_count++;
					
				$enemy->recalculate();
			}
			
			if ($enemy_dead_count >= sizeof($this->enemy_group))
			{
				array_push($log, array("winner" => "Player Group"));
				$not_finished = true;
			}
			
			// Let the battle goes if it's not finished
			if($not_finished == false)
			{
				echo "<br />\n";
				// Count all the Turn Counter
				//===========================================================
				// Turn Counter Box that stores all turn from all enemies & players
				$tc_box = array();
				
				foreach($this->player_group as $player)
				{
					array_push($tc_box, $player->curr_tc);
				}
				
				foreach($this->enemy_group as $enemy)
				{
					array_push($tc_box, $enemy->curr_tc);
				}
				
				// Get the shortest turn
				$min_tc = min($tc_box);
				
				// Reduce TC for everyone
				foreach($this->player_group as $player)
				{
					$player->curr_tc -= $min_tc;
					
					// Check if it's player's turn
					echo $player->name . " \t | Current TC: " .$player->curr_tc ."<br />\n";
					if($player->curr_tc <= 0)
					{
						// TO-DO: STOP here, wait for input
						$decide = floor(rand(0, 10));
						
						do {
							$target = floor(rand(0, sizeof($this->enemy_group) - 1));
						} while($this->enemy_group[$target]->hp <= 0);
						
						if($decide <= 4)
							array_push($log, $this->basic_attack($player, $this->enemy_group[$target]));
						else
						{
							$skill_decision = floor(rand(0, sizeof($player->skills) - 1));
							$player->skills[$skill_decision]->caster = &$player;
							$player->skills[$skill_decision]->target = &$this->enemy_group[$target];
							array_push($log, $player->skills[$skill_decision]->execute());
						}
					}
				}
				
				foreach($this->enemy_group as $enemy)
				{
					$enemy->curr_tc -= $min_tc;
					
					// Check if it's enemy's turn
					echo $enemy->name . " \t | Current TC: " . $enemy->curr_tc ."<br />\n";
					if($enemy->curr_tc <= 0)
					{
						$decide = floor(rand(0, 10));
						
						do {
							$target = floor(rand(0, sizeof($this->player_group) - 1));
						} while($this->player_group[$target]->hp <= 0);
						
						if($decide <= 4)
							array_push($log, $this->basic_attack($enemy, $this->player_group[$target]));
						else
						{
							$skill_decision = floor(rand(0, sizeof($enemy->skills) - 1));
							$enemy->skills[$skill_decision]->caster = &$enemy;
							$enemy->skills[$skill_decision]->target = &$this->player_group[$target];
							array_push($log, $enemy->skills[$skill_decision]->execute());
						}
					}
				}
			}
		}
		
		//header('Content-Type: application/json');
		echo json_encode($log);
	}
	
	// Later change this to object oriented
	// All the functions for skills & attacks should be written hardcodedly
	private function basic_attack(&$from, &$to)
	{
		$dmg_reduction = (150 - $to->def) / 150;
		$damage = round(rand($from->atk-5, $from->atk) * $dmg_reduction);
		
		$to->hp -= $damage;
		
		// Increase the TC
		$from->curr_tc += $from->b_tc;
		
		return array("basic_attack" => array("from" => $from->name, "to" => $to->name, "damage" => $damage));
	}
	
	private function bash(&$from, &$to)
	{
		$hp_usage = 0;
		$mp_usage = 10;
		$ki_usage = 3;
		$dmg_multiplier = 2.0;
		$dmg_reduction = (150 - $to->def) / 150;
		$damage = round(rand($from->atk-6, $from->atk+2) * $dmg_multiplier * $dmg_reduction);
		
		// Use the hp, mana, and ki
		$from->hp -= $hp_usage;
		$from->mp -= $mp_usage;
		$from->ki -= $ki_usage;
		
		$to->hp -= $damage;
		
		// Increase the TC
		$from->curr_tc += round($from->b_tc * 1.82);
		
		return array("s_bash" => array("from" => $from->name, "to" => $to->name, "damage" => $damage));
	}
	
	private function fireball(&$from, &$to)
	{
		$hp_usage = 0;
		$mp_usage = 45;
		$ki_usage = 0;
		$dmg_multiplier = 2.5;
		$dmg_reduction = (150 - $to->mdef) / 150;
		$damage = round(rand($from->matk-5, $from->matk+3) * $dmg_multiplier * $dmg_reduction);
		
		// Use the hp, mana, and ki
		$from->hp -= $hp_usage;
		$from->mp -= $mp_usage;
		$from->ki -= $ki_usage;
		
		$to->hp -= $damage;
		
		// Increase the TC
		$from->curr_tc += round($from->b_tc * 1.12);
		
		return array("s_fireball" => array("from" => $from->name, "to" => $to->name, "damage" => $damage));
	}
	
	private function frostbolt(&$from, &$to)
	{
		$hp_usage = 0;
		$mp_usage = 70;
		$ki_usage = 0;
		$dmg_multiplier = 1.15;
		$dmg_reduction = (150 - $to->mdef) / 150;
		
		// Use the hp, mana, and ki
		$from->hp -= $hp_usage;
		$from->mp -= $mp_usage;
		$from->ki -= $ki_usage;
		
		$log = array();
		for($i=1; $i<=2; $i++)
		{
			$damage = round(rand($from->matk-7, $from->matk+7) * $dmg_multiplier * $dmg_reduction);
			
			$to->hp -= $damage;
			array_push($log, array("from" => $from->name, "to" => $to->name, "damage" => $damage));
		}
		
		// Increase the TC
		$from->curr_tc += round($from->b_tc * 2.31);
		
		return array("s_frostbolt" => $log);
	}
	
	private function quadblow(&$from, &$to)
	{
		$hp_usage = 0;
		$mp_usage = 10;
		$ki_usage = 20;
		$dmg_multiplier = 0.85;
		$dmg_reduction = (150 - $to->def) / 150;
		
		// Use the hp, mana, and ki
		$from->hp -= $hp_usage;
		$from->mp -= $mp_usage;
		$from->ki -= $ki_usage;
		
		$log = array();
		for($i=1; $i<=4; $i++)
		{
			$damage = round(rand($from->atk-4, $from->atk+2) * $dmg_multiplier * $dmg_reduction);
			
			$to->hp -= $damage;
			array_push($log, array("from" => $from->name, "to" => $to->name, "damage" => $damage));
		}
		
		// Increase the TC
		$from->curr_tc += round($from->b_tc * 2.24);
		
		return array("s_quadblow" => $log);
	}
	
	private function heal(&$from, &$to)
	{
		$hp_usage = 0;
		$mp_usage = 35;
		$ki_usage = 0;
		$dmg_multiplier = 2.25;
		$dmg_reduction = (150 - $to->mdef) / 150;
		$damage = round(rand($from->matk-2, $from->matk+2) * $dmg_multiplier);
		
		// Use the hp, mana, and ki
		$from->hp -= $hp_usage;
		$from->mp -= $mp_usage;
		$from->ki -= $ki_usage;
		
		$to->hp += $damage;
		
		// Increase the TC
		$from->curr_tc += round($from->b_tc * 1.12);
		
		return array("s_heal" => array("from" => $from->name, "to" => $to->name, "heal" => $damage));
	}
}

/* End of file welcome.php */
/* Location: ./application/controllers/welcome.php */